package JavaFoundation.myLock.volataileTest;

public class SingletonDemo{
    //private static SingletonDemo instance = null;
    private static volatile SingletonDemo instance = null;
    private SingletonDemo(){
        System.out.println(Thread.currentThread().getName()+"单例模式的构造方法");
    }
//    public static synchronized SingletonDemo getInstance(){
//        if(instance==null){
//            instance= new SingletonDemo();
//        }
//        return instance;
//    }

    //DCL(Double Chek Lock双端检索机制)
    /*
    这种双端检索机制的成功率可能是99.99%。但编译器底层有指令重排，可能有一次就会出现错误。
    双端检索机制不一定是线程安全的，原因是有指令重排的存在，加入volatile可以禁止指令重排，
    原因在于某一线程执行到第一次检测，读取到的instance不为null时(但是它引用的对象可能没有完成初始化)。
    instance= new SingletonDemo();可以分为以下3个步骤
    memory = allocate();//1.分配对象内存空间
    instance(memory);   //2.初始化对象
    instance = memory;  //3.设置instance执行刚才分配的内存地址，此时instance != null;
    步骤2和3是不存在数据依赖关系的，而且无论是否重排程序的执行结果在单线程中是并没有改变的，因此这种重排优化是允许的。
     在并发情况下有可能出现的情况(优化后)：
     memory = allocate();//1.分配对象内存空间
     instance = memory;  //3.设置instance执行刚才分配的内存地址，此时instance != null;但对象还没有完成初始化
     instance(memory);   //2.初始化对象
     此时如果有线程在instance = memory;后来取值，虽然instance != null，但是instance还没有初始化完成，
     此时就会出现线程不安全的问题。
     */
    public static  SingletonDemo getInstance(){
        if(instance==null){
            synchronized (SingletonDemo.class){
                if(instance == null){
                    instance= new SingletonDemo();
                }
            }
        }
        return instance;
    }


    public static void main(String[] args) {
        //单机版的单例模式
//        System.out.println(SingletonDemo.getInstance()==SingletonDemo.getInstance());
//        System.out.println(SingletonDemo.getInstance()==SingletonDemo.getInstance());
//        System.out.println(SingletonDemo.getInstance()==SingletonDemo.getInstance());
        /*
        多线程并发的情况下就不是  构造器加synchronized是可以解决这个问题的，但...
         */
        for (int i = 1; i <= 10; i++) {
            new Thread(()->{
                SingletonDemo.getInstance();
            },String.valueOf(i)).start();
        }

    }
}
